package com.one.blocks.eds.core;

import com.one.blocks.eds.config.properties.EdsRemoteProperties;
import com.one.blocks.eds.exception.EdsException;
import com.zaxxer.hikari.HikariDataSource;
import com.zaxxer.hikari.HikariPoolMXBean;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.util.Optional;
import java.util.Properties;

/**
 * @author <a href="mailto:idler41@163.com">linfuxin</a> created on 2025-08-08 16:10:04
 */
@Slf4j
@RequiredArgsConstructor
public class ExpireDataSourceManager {

    private final ExpireDataSource expireDataSource;

    public boolean containsKey(String dsKey) {
        return expireDataSource.targetDataSources.containsKey(dsKey);
    }

    public HikariPoolMXBean getHikariPoolMXBean(String dsKey) {
        return Optional.ofNullable(expireDataSource.targetDataSources.get(dsKey))
                .map(holder -> ((HikariDataSource) holder.getDataSource()).getHikariPoolMXBean())
                .orElse(null);
    }

    public boolean test(EdsRemoteProperties edsRemoteProperties) {
        ClassLoader driverClassLoader = expireDataSource.getClassLoaderFromCache(edsRemoteProperties, Thread.currentThread().getContextClassLoader());
        try {
            Class<?> driverClass = driverClassLoader.loadClass((String) edsRemoteProperties.getHikariProperties().get("driverClassName"));
            Driver driver = (Driver) driverClass.newInstance();
            Properties properties = edsRemoteProperties.getHikariProperties();
            /**
             * 老版本驱动可能不能识别除用户名与密码之外的配置，所以这里不能直接用HikariProperties
             * @see com.zaxxer.hikari.util.DriverDataSource#getConnection
             */
            Properties testProperties = new Properties();
            String jdbcUrl = properties.getProperty("jdbcUrl");
            testProperties.put("user", properties.getProperty("username"));
            testProperties.put("password", properties.getProperty("password"));
            try (Connection connection = driver.connect(jdbcUrl, testProperties)) {
                return connection.isValid(5);
            } catch (SQLException e) {
                throw new EdsException(e);
            }
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            throw new EdsException(e);
        }
    }

    public void evict(String dsKey) {
        if (expireDataSource.staticDataSources.containsKey(dsKey)) {
            log.warn("静态数据源不能动态操作!dsKey={}", dsKey);
            return;
        }
        expireDataSource.targetDataSources.computeIfPresent(dsKey, (k, v) -> {
            try {
                v.setRemoved(true);
                expireDataSource.evictQueue.put(v);
                expireDataSource.targetDataSources.remove(dsKey);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new EdsException("evictQueue put线程中断!");
            }
            // 返回null，删除键
            return null;
        });
    }

    public void replace(String dsKey) {
        if (expireDataSource.staticDataSources.containsKey(dsKey)) {
            log.warn("静态数据源不能动态操作!dsKey={}", dsKey);
            return;
        }
        ExpireDataSourceHolder newVal = expireDataSource.createDataSource(dsKey);
        ExpireDataSourceHolder oldVal = expireDataSource.targetDataSources.put(dsKey, newVal);
        if (oldVal != null) {
            try {
                if (!oldVal.isRemoved()) {
                    oldVal.setRemoved(true);
                    expireDataSource.evictQueue.put(oldVal);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new EdsException("evictQueue put线程中断!");
            }
        }
    }
}
